#include "oled_menu.h"

extern u8g2_t u8g2;

// main menu
menu_meta_t main_menu_meta =
{
  .menu_len = 10,
  .init_func = NULL
};

menu_t main_menu[10] =
{
  {&main_menu_meta, "AT32F435 Hello", NULL, & say_hello, NULL},
  {&main_menu_meta, "PID INPUT TEST", NULL, NULL, NULL},
  {&main_menu_meta, "ADD Contrast", NULL, NULL, NULL},
  {&main_menu_meta, "Remove Contrast", NULL, NULL, NULL},
  {&main_menu_meta, "Menu1", NULL, & say_hello, NULL},
  {&main_menu_meta, "Menu2", NULL, & say_hello, NULL},
  {&main_menu_meta, "Menu3", NULL, & say_hello, NULL},
  {&main_menu_meta, "Menu4", NULL, & say_hello, NULL},
  {&main_menu_meta, "Menu5", NULL, & say_hello, NULL},
  {&main_menu_meta, "Menu6", NULL, & say_hello, NULL},
};

// pid menu
menu_meta_t pid_menu_meta =
{
  .menu_len = 5,
  .init_func = pid_menu_init
};

menu_t pid_menu[5] =
{
  {&pid_menu_meta, "", & pid_val_remove, & pid_val_add, NULL},
  {&pid_menu_meta, "", & pid_val_remove, & pid_val_add, NULL},
  {&pid_menu_meta, "", & pid_val_remove, & pid_val_add, NULL},
  {&pid_menu_meta, "SAVE", NULL, & pid_save, NULL},
  {&pid_menu_meta, "BACK", NULL, NULL, NULL},
};

menu_t* current_menu = main_menu; // current menu
__IO uint8_t scroll_num = 0; // fold item num
__IO int8_t select_item = 0; // currently selected item index
__IO uint8_t need_confirm = 0; // whether confirmation is required (dialog scene)

void menu_init(void)
{
  // initial font
  u8g2_SetFont(&u8g2, u8g2_font_t0_11_tf);
  // set the font coordinates to the upper left corner
  u8g2_SetFontPosTop(&u8g2);

  // fill menu items
  main_menu[1].children_menu = (struct menu_t*)pid_menu;
  pid_menu[4].children_menu = (struct menu_t*)main_menu;

  // refresh menu
  menu_refresh();
}

void menu_refresh(void)
{
  u8g2_SetDrawColor(&u8g2, 2);
  u8g2_SetFontMode(&u8g2, 1);

  // draw frame
  for(uint8_t frame = 1; frame <= FRAME_NUM; frame++)
  {
    u8g2_ClearBuffer(&u8g2);
    // If the display length is exceeded, the last menu item is selected
    uint8_t point_i = select_item > 4 ? 4 : select_item;
    // draws a box and arrow for the currently selected option
    u8g2_DrawBox(&u8g2, 0, point_i * FONT_HEIGHT, frame * FRAME_X_SEG, frame * FRAME_Y_SEG);
    u8g2_DrawStr(&u8g2, 1, point_i * FONT_HEIGHT, ">");

    // draw menu items
    for(uint8_t i = 0; i < 5; i++)
    {
      // Remove collapsed menu items
      u8g2_DrawStr(&u8g2, 8, i * FONT_HEIGHT, current_menu[i + scroll_num].disp_str);
    }
    u8g2_SendBuffer(&u8g2);
  }

  // disable buzzer
  tmr_channel_value_set(TMR2, TMR_SELECT_CHANNEL_3, 0);
}

void menu_up(void)
{
  // Whether in the dialog page
  if(need_confirm)
  {
    return;
  }
  uint8_t menu_len = current_menu->menu_meta->menu_len;
  int8_t new_item = select_item - 1;
  // Out of bounds inspection
  if(new_item == -1)
  {
    new_item = menu_len - 1;
  }
  /*
  rolling algorithm:
  If it is greater than the number of menus, the above menu will be collapsed.
  example: new_item = 5, The scroll amount will be equal to 1.
  It will be displayed from the second menu (index 1)
  */
  if(new_item > 4)
  {
    scroll_num = new_item - 4;
  }
  else
  {
    scroll_num = 0;
  }
  buzzer_godown();
  // commit
  select_item = new_item;
  menu_refresh();
}

void menu_down(void)
{
  // Whether in the dialog page
  if(need_confirm)
  {
    return;
  }
  uint8_t menu_len = current_menu->menu_meta->menu_len;
  int8_t new_item = select_item + 1;
  // Out of bounds inspection
  if(new_item == menu_len)
  {
    scroll_num = 0;
    new_item = 0;
  }
  if(new_item > 4)
  {
    scroll_num = new_item - 4;
  }
  else
  {
    scroll_num = 0;
  }
  buzzer_godown();
  // commit
  select_item = new_item;
  menu_refresh();
}

void menu_back(void)
{
  // Whether in the dialog interface
  if(need_confirm)
  {
    return;
  }
  // execute callback
  if(current_menu[select_item].func0 != NULL)
  {
    current_menu[select_item].func0(select_item);
    return;
  }
}

void menu_go(void)
{
  // Whether in the dialog page
  if(need_confirm)
  {
    // close dialog
    need_confirm = 0;
    menu_refresh();
    return;
  }
  // execute callback
  if(current_menu[select_item].func1 != NULL)
  {
    current_menu[select_item].func1(select_item);
    return;
  }
  // jump page
  if(current_menu[select_item].children_menu != NULL)
  {
    current_menu = (menu_t*)current_menu[select_item].children_menu;
    scroll_num = 0;
    select_item = 0;
    // execute page init callback
    if(current_menu->menu_meta->init_func != NULL)
    {
      current_menu->menu_meta->init_func();
    }
    menu_refresh();
  }
}

void menu_dialog(const char* str, const char* str2)
{
  u8g2_SetDrawColor(&u8g2, 0);
  need_confirm = 1;
  u8g2_DrawRBox(&u8g2, 3, 3, 122, 58, 7);
  u8g2_SetDrawColor(&u8g2, 1);
  u8g2_DrawRFrame(&u8g2, 3, 3, 122, 58, 7);
  u8g2_DrawStr(&u8g2, 8, 8, str);
  if(str2 != NULL)
  {
    u8g2_DrawStr(&u8g2, 8, 19, str2);
  }
  u8g2_DrawStr(&u8g2, 8, 39, "[ BACK ]");
  u8g2_SendBuffer(&u8g2);
}

void say_hello(uint8_t select_item)
{
  char log_buf[32];
  snprintf(log_buf, 32, "select_item = %d", select_item);
  menu_dialog("Hello AT32F435", log_buf);
}
